﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Aop.Api.Domain;
using Lg.Core.Extensions;
using NPOI.POIFS.FileSystem;

namespace Lg.Core.SMS.YM
{
    public class SMS : ISMS
    {
        //短信参数
        private string appId = "";
        // 密钥
        private string secretKey = "";
        // 接口地址
        private string url = "";
        //接口域名
        private string host = "";
        private string signName = "";
        //参数压缩
        private bool isCompress = false;//是否压缩，默认否
        #region [构造方法]
        [Obsolete]
        public SMS()
        {
            string filePath = Tools.MapPath("/App_Data/LgConfig.xml");
            if (File.Exists(filePath))
            {
                try
                {
                    XDocument document = XDocument.Load(filePath);
                    //获取到XML的根元素进行操作
                    XElement _root = document.Root!;
                    XElement wx = _root.Element("SMS_YM")!;
                    //获取根元素下的所有子元素
                    // IEnumerable<XElement> enumerable = _root.Elements();
                    this.appId = wx.Element("appId")!.Value;
                    this.secretKey = wx.Element("secretKey")!.Value;
                    this.url = wx.Element("url")!.Value;
                    this.signName = wx.Element("signName")!.Value;
                }
                catch (Exception ex)
                {
                    throw new Exception($"获取主要参数失败！{ex.Message}");
                }

            }
            else
            {
                Log.Error("File", "配置文件未找到");
            }
        }
        [Obsolete]
        public SMS(XElement root)
        {
            try
            {
                this.appId = root.Element("appId")!.Value;
                this.secretKey = root.Element("secretKey")!.Value;
                this.url = root.Element("url")!.Value;
                this.signName = root.Element("signName")!.Value;
            }
            catch (Exception ex)
            {
                throw new Exception($"获取主要参数失败！{ex.Message}");
            }

        }
       
        public SMS(string appid, string secret, string url, string sign)
        {
            this.appId = appid;
            this.secretKey = secret;
            this.url = url;
            this.signName = sign;
        }

        /// <summary>
        /// 支持使用xml或是json配置文件
        /// </summary>
        /// <param name="fileType">文件类型</param>
        /// <param name="filePath">文件路径</param>
        /// <exception cref="Exception"></exception>
        public SMS(SMSConfigFileTypeOptions fileType, string? filePath = null)
        {
            if (fileType == SMSConfigFileTypeOptions.json)
            {
                IJsonHelper jsonHelper = new JsonHelper(filePath);
                this.host = jsonHelper.GetValue("SMS_YM.host");
                this.appId = jsonHelper.GetValue("SMS_YM.appId");
                this.secretKey = jsonHelper.GetValue("SMS_YM.secretKey");
                this.signName = jsonHelper.GetValue("SMS_YM.signName");
            }
            else if (fileType == SMSConfigFileTypeOptions.xml)
            {
                filePath = filePath ?? Tools.MapPath("/App_Data/LgConfig.xml");
                if (File.Exists(filePath))
                {
                    try
                    {
                        XDocument document = XDocument.Load(filePath);
                        //获取到XML的根元素进行操作
                        XElement _root = document.Root!;
                        XElement wx = _root.Element("SMS_YM")!;
                        //获取根元素下的所有子元素
                        // IEnumerable<XElement> enumerable = _root.Elements();
                        this.appId = wx.Element("appId")!.Value;
                        this.secretKey = wx.Element("secretKey")!.Value;
                        this.url = wx.Element("url")!.Value;
                        this.signName = wx.Element("signName")!.Value;
                    }
                    catch (Exception ex)
                    {
                        throw new Exception($"获取主要参数失败！{ex.Message}");
                    }

                }
                else
                {
                    Log.Error("File", "配置文件未找到");
                }
            }
        }

        /// <summary>
        /// 通过参数实体构造
        /// </summary>
        /// <param name="config"></param>
        /// <exception cref="Exception"></exception>
        public SMS(YMConfigEntity config)
        {
            this.appId = config.AppId??throw new Exception("缺少AppId");
            this.secretKey = config.SecretKey ?? throw new Exception("缺少secretKey");
            this.host = config.Host ?? throw new Exception("缺少host");
            this.signName = config.SignName ?? "";
        }
        #endregion       

        #region [公共方法]
        public string Send(ISMSEntity entity,Action<string>? action=null)
        {
            SMSEntity model = (SMSEntity)entity;
            //添加签名
            model.content = this.signName + model.content;
            string result = "";
            Hashtable headerhs = new Hashtable();
            headerhs.Add("appId", this.appId);
            string jsondata = model.ToJsonString();
            
            #region 【1】判断是否需要压缩,然后生成参数并提交发送
            if (isCompress)
            {
                headerhs.Add("gzip", "on");//先压缩成byte再加密
                result = postdata(this.url, GzipHelper.GZipCompressString(jsondata)!.ToAesEncryptByteArray(this.secretKey), headerhs, Encoding.UTF8, this.secretKey);
            }
            else
            {
                result = postdata(this.url, jsondata.AesEncryptForByteArray(this.secretKey), headerhs, Encoding.UTF8, this.secretKey);
            }
            if(action != null)
            {
                Task.Run(()=>{
                    action(result);
                });
            }
            #endregion
            return result;
        }
        /// <summary>
        /// 通过BaseSMS实体发送短信，将实体转化为YM.SMSEntity,
        /// 方法不默认添加签名，需调用者在短信内容中自行添加
        /// </summary>
        /// <param name="baseModel"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        public async Task<BaseSendResult?> SendAsync(BaseSMS baseModel, Action<BaseSendResult>? onSucess=null)
        {
            return await Task.Run(() =>
            {
                SMSEntity model = new SMSEntity
                {
                    content = baseModel.Content,
                    customSmsId = baseModel.CustomSmsId,
                    extendedCode = baseModel.ExtendCode,
                    mobile = baseModel.Phone,
                    requestTime = DateTime.Now.Ticks,
                    requestValidPeriod = 30
                };
                BaseSendResult? result = null;
                string jsondata = model.ToJsonString();
                HttpClient httpClient = new HttpClient();
                httpClient.DefaultRequestHeaders.Add("appId", appId);
                byte[] byteArray = jsondata.AesEncryptForByteArray(secretKey);
                HttpResponseMessage response = httpClient.PostAsync($"{this.host}/inter/sendSingleSMS", new ByteArrayContent(byteArray)).Result;
                response.EnsureSuccessStatusCode();
                using Stream stream = response.Content.ReadAsStream();
                string code = response.Headers.GetValues("result").FirstOrDefault()!;
                if (code == "SUCCESS")
                {
                    byte[] bytes = StreamToBytes(stream);
                    var reports = bytes.ToAesDecryptString(secretKey).ToModel<YMSendResultEntity>();
                    if (reports != null)
                    {
                        result = reports.ToBaseSendResult();
                        if (onSucess != null)
                        {
                            Task.Run(() =>
                            {
                                onSucess(result);
                            });
                        }
                    }

                }
                return result;
            });
            
        }
        public static async Task<BaseSendResult?> SendAsync(BaseSMS baseModel, string appId, string secretKey, string host, Action<BaseSendResult>? onSucess = null)
        {
            return await Task.Run(() =>
            {
                SMSEntity model = new SMSEntity
                {
                    content = baseModel.Content,
                    customSmsId = baseModel.CustomSmsId,
                    extendedCode = baseModel.ExtendCode,
                    mobile = baseModel.Phone,
                    requestTime = DateTime.Now.Ticks,
                    requestValidPeriod = 30
                };
                BaseSendResult? result = null;
                string jsondata = model.ToJsonString();
                HttpClient httpClient = new HttpClient();
                httpClient.DefaultRequestHeaders.Add("appId", appId);
                byte[] byteArray = jsondata.AesEncryptForByteArray(secretKey);
                HttpResponseMessage response = httpClient.PostAsync($"{host}/inter/sendSingleSMS", new ByteArrayContent(byteArray)).Result;
                response.EnsureSuccessStatusCode();
                using Stream stream = response.Content.ReadAsStream();
                string code = response.Headers.GetValues("result").FirstOrDefault()!;
                if (code == "SUCCESS")
                {
                    byte[] bytes = StreamToBytes(stream);
                    var reports = bytes.ToAesDecryptString(secretKey).ToModel<YMSendResultEntity>();
                    if (reports != null)
                    {
                        result = reports.ToBaseSendResult();
                        if (onSucess != null)
                        {
                            Task.Run(() =>
                            {
                                onSucess(result);
                            });
                        }
                    }

                }
                return result;
            });

        }

        /// <summary>
        /// 获取状态报告
        /// </summary>
        /// <param name="number">获取数量</param>
        /// <param name="appid">获取帐户的APPID,不传值则用SMS实例化的appid参数值</param>
        /// <param name="secretKey">获取帐户的secretKey，不传值则用SMS实例化的secretKey参数值</param>
        /// <returns></returns>
        public async Task<List<BaseReport>?> GetReportAsync(int number=300,string? appid=null,string? secretKey=null) 
        {
            return await Task.Run(() =>
            {
                List<BaseReport>? result = null;
                appid = appid ?? this.appId;
                secretKey = secretKey ?? this.secretKey;
                RtMsg rtmsg = new RtMsg() { code = 400, msg = "未知错误!" };
                var jsondata = "{\"number\":" + number + ",\"requestTime\":" + DateTime.Now.Ticks.ToString() + ",\"requestValidPeriod\":" + 3600 + "}";
                byte[] byteArray = jsondata.AesEncryptForByteArray(secretKey);
                HttpClient httpClient = new HttpClient();
                httpClient.DefaultRequestHeaders.Add("appId", appId);
                HttpResponseMessage response = httpClient.PostAsync($"{this.host}/inter/getReport", new ByteArrayContent(byteArray)).Result;
                response.EnsureSuccessStatusCode();
                using Stream stream = response.Content.ReadAsStream();
                string code = response.Headers.GetValues("result").FirstOrDefault()!;
                if (code == "SUCCESS")
                {
                    byte[] bytes = StreamToBytes(stream);
                    var reports= bytes.ToAesDecryptString(secretKey).ToList<YM.ReportEntity>();
                    if(reports != null)
                    {
                        result = reports.ToBaseReportList();
                    }
                    
                }
                return result;
            });
            

        }
        /// <summary>
        /// 获取上行数据
        /// </summary>
        /// <param name="number">获取数量</param>
        /// <param name="appid">默认为构造SMS时传入的appid</param>
        /// <param name="secretKey">默认为构造SMS时传入的secretKey</param>
        /// <returns></returns>
        public async Task<List<BaseReply>?> GetReplyAsync(int number = 500, string? appid = null, string? secretKey = null)
        {
            return await Task.Run(() =>
            {
                List<BaseReply>? result = null;
                appid = appid ?? this.appId;
                secretKey = secretKey ?? this.secretKey;
                var jsondata = "{\"number\":" + number + ",\"requestTime\":" + DateTime.Now.Ticks.ToString() + ",\"requestValidPeriod\":" + 3600 + "}";
                byte[] byteArray = jsondata.AesEncryptForByteArray(secretKey);
                HttpClient httpClient = new HttpClient();
                httpClient.DefaultRequestHeaders.Add("appId", appId);
                HttpResponseMessage response = httpClient.PostAsync($"{this.host}/inter/getMo", new ByteArrayContent(byteArray)).Result;
                response.EnsureSuccessStatusCode();
                using Stream stream = response.Content.ReadAsStream();
                string code = response.Headers.GetValues("result").FirstOrDefault()!;
                if (code == "SUCCESS")
                {
                    byte[] bytes = StreamToBytes(stream);
                    var reports = bytes.ToAesDecryptString(secretKey).ToList<YM.ReplyEntity>();
                    if (reports != null)
                    {
                        result = reports.ToBaseReplyList();
                    }

                }
                return result;
            });


        }
        #endregion
        #region [静态方法]    
        #endregion
        #region [私有方法]
        /// <summary>
        /// post方法
        /// </summary>
        /// <param name="postUrl">地址</param>
        /// <param name="paramData">参数</param>
        /// <param name="Header">请求头</param>
        /// <param name="dataEncode">编码</param>
        /// <returns></returns>
        static string postdata(string postUrl, Byte[] paramData, Hashtable Header, Encoding dataEncode, string secretKey)
        {
            try
            {
                RtMsg rtmsg = new RtMsg() { code = 400, msg = "未知错误!" };
                byte[] byteArray = paramData;
                using HttpClient httpClient = new HttpClient();
                if (Header != null)
                {
                    foreach (DictionaryEntry de in Header)
                    {
                        httpClient.DefaultRequestHeaders.Add(de.Key.ToString()!, de.Value!.ToString());
                    }
                }
                using HttpResponseMessage response =  httpClient.PostAsync(postUrl, new ByteArrayContent(byteArray)).Result;
                response.EnsureSuccessStatusCode();
                using Stream stream = response.Content.ReadAsStream();
                string code = response.Headers.GetValues("result").FirstOrDefault()!;
                if (code == "SUCCESS")
                {
                    byte[] bytes = StreamToBytes(stream);
                    rtmsg.code = 0;
                    rtmsg.msg = code;
                    rtmsg.data= bytes.ToAesDecryptString(secretKey).ToModel<SMSEntity>() ;
                }
                else
                {
                    rtmsg.msg=code;
                }
                return rtmsg.ToJsonString();
            }
            catch (Exception e)
            {
               throw new Exception(e.Message, e);
                //错误日志
            }
        }
        static byte[] StreamToBytes(Stream stream)
        {
            byte[] bytes = new byte[stream.Length];
            stream.Read(bytes, 0, bytes.Length);
            // 设置当前流的位置为流的开始
            stream.Seek(0, SeekOrigin.Begin);
            return bytes;
        }

        
        #endregion


    }
}
